﻿namespace Ops.Host.Core.Services;

internal sealed class CustomService : ScadaDomainService, ICustomService
{
    private const string PLC_Sign_Marking = nameof(PLC_Sign_Marking); // 打标前缀
    private const string PLC_Sign_Card = nameof(PLC_Sign_Card); // 刷卡前缀
    private const string PLC_Sign_SpotCheck = nameof(PLC_Sign_SpotCheck); // 点检前缀

    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger _logger;

    public CustomService(IServiceProvider serviceProvider, ILogger<CustomService> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;

    }

    public async Task<ReplyResult> HandleAsync(ForwardData data)
    {
        // 打标
        if (data.Tag.StartsWith(PLC_Sign_Marking))
        {
            return await HandleMarkingAsync(data);
        }

        // 刷卡
        if (data.Tag.StartsWith(PLC_Sign_Card))
        {
            return await HandleCardSwipingsync(data);
        }
        
        // 点检
        if (data.Tag.StartsWith(PLC_Sign_SpotCheck))
        {
            return await HandleSpotCheckAsync(data);
        }

        return Ok();
    }

    private async Task<ReplyResult> HandleMarkingAsync(ForwardData data)
    {
        var sn = data.GetString("PLC_Marking_SN");
        if (string.IsNullOrWhiteSpace(sn))
        {
            return Ok();
        }

        try
        {
            using var scope = _serviceProvider.CreateScope();
            var markingService = scope.ServiceProvider.GetRequiredService<IPtMarkingService>();

            // 记录SN
            PtMarking marking = new()
            {
                SN = sn,
                MarkingTime = DateTime.Now,
            };
            await markingService.AddOrUpdateMarkingAsync(marking);

            // 推送消息
            await MessageTaskQueueManager.Default.QueueAsync(new Message(data.Schema.Line, data.Schema.Station, MessageClassify.Marking, "", marking.SN));
            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"[CustomService] 打标信息异常");
        }

        return Error();
    }

    private async Task<ReplyResult> HandleCardSwipingsync(ForwardData data)
    {
        var ret = From(3); // PLC 指定成功后需要返回3
        try
        {
            var num = data.Tag[(PLC_Sign_Card.Length + 1)..]; // 取末尾的序号
            var cardNo = data.GetString($"PLC_Card_CardNo_{num}"); // 发送过来的卡信息，其中包含设备信息。
            if (string.IsNullOrWhiteSpace(cardNo))
            {
                return Error(4);
            }

            var (ok, cardNo2, cardDeviceNo) = SplitCard(cardNo.Trim());
            if (!ok)
            {
                _logger.LogWarning("[CustomService:CardSwiping] 卡号分隔异常，刷卡信息{0}；卡号：{1}；设备：{2}", cardNo, cardNo2, cardDeviceNo);
                return Error(4);
            }

            using var scope = _serviceProvider.CreateScope();

            // 检查卡号是否存在
            var cardService = scope.ServiceProvider.GetRequiredService<ISysCardService>();
            var cardInfo = await cardService.GetByCardNoAsync(cardNo2);
            if (cardInfo == null)
            {
                return Error(4);
            }

            var cardRecordService = scope.ServiceProvider.GetRequiredService<ISysCardRecordService>();
            SysCardRecord item = new()
            {
                LineCode = data.Schema.Line,
                StationCode = data.Schema.Station,
                CardNo = cardNo2,
                Owner = cardInfo.Owner,
                CardDeviceName = data.Name ?? "",
                CardDeviceNo = cardDeviceNo,
            };
            await cardRecordService.AddCardRecordAsync(item);

            // 回写卡号等级
            ret.AddValue($"MES_Card_Level_{num}", Convert.ToInt16((int)cardInfo!.CardLevel));

            // 推送消息
            await MessageTaskQueueManager.Default.QueueAsync(new Message(item.LineCode, item.StationCode, 
                MessageClassify.CardSwiping, item.CardNo, (item.CardDeviceName, item.CardDeviceNo, item.Owner)));

            return ret;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"[CustomService] 刷卡信息异常");
            return Error();
        }

        (bool ok, string cardNo, string cardDeviceNo) SplitCard(string card)
        {
            int len = 10; // 卡机设备长度
            // 刷卡信息长度必须大于刷卡机设备号长度
            if (card.Length <= len)
            {
                return (false, "", "");
            }

            // 设备号在前，卡号在后。
            return (true, card[len..], card[..len]);
        }
    }

    private async Task<ReplyResult> HandleSpotCheckAsync(ForwardData data)
    {
        try
        {
            using var scope = _serviceProvider.CreateScope();

            var sysDictDataService = scope.ServiceProvider.GetRequiredService<ISysDictDataService>();
            // 从字典中查找对应的警报信息，若字典中没有设置，不会存储对应警报信息。
            var dicts = await sysDictDataService.GetDicsByCodeAsync(DictCodeEnum.SpotCheck.ToString());
            if (!dicts.Any())
            {
                return Ok();
            }

            // 1 => "防错验证请求",
            // 2 => "防错验证全无检测通过",
            // 3 => "防错验证零件检测通过",
            // 4 => "防错验证防漏防错通过",
            // 5 => "防错验证完成"
            var num = data.Tag[(PLC_Sign_SpotCheck.Length + 1)..]; // 取末尾的序号
            var item = data.GetInt($"PLC_SpotCheck_Item_{num}");
            var spotCheckDict = dicts.FirstOrDefault(s => s.Value == item.ToString());
            if (spotCheckDict == null)
            {
                return Ok();
            }
           
            var spotCheck = new DvSpotCheck
            {
                LineCode = data.Schema.Line,
                StationCode = data.Schema.Station,
                Tooling = data.Name ?? "",
                Item = spotCheckDict.Name,
                Value = "",
                IsPass = true,
            };

            // 检查卡号是否存在
            var spotCheckService = scope.ServiceProvider.GetRequiredService<IDvSpotCheckService>();
            await spotCheckService.AddSpotCheckAsync(spotCheck);

            // 推送消息
            await MessageTaskQueueManager.Default.QueueAsync(new Message(spotCheck.LineCode, spotCheck.StationCode, 
                MessageClassify.SpotCheck, spotCheck.Tooling!, (spotCheck.Item, spotCheck.IsPass)));

            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"[CustomService] 点检信息异常");
            return Error();
        }
    }
}
